home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / perl / mac-perl / gs_102st.bin / GUSI / GUSIPPC.cp / GUSIPPC.cp
Encoding:
Text File  |  1992-12-17  |  14.1 KB  |  744 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIPPC.cp        -    PPC Sockets
  4. Author    :    Matthias Neeracher
  5. Started    :    18May92                                Language    :    MPW C/C++
  6. Modified    :    02Aug92    MN    Put some further work in
  7.                 03Aug92    MN    Approximately correct, except for sync/async
  8.                 03Aug92    MN    Introduce additional buffering
  9.                 10Aug92    MN    Correct select()
  10.                 30Aug92    MN    Move hasPPC here
  11.                 07Sep92    MN    Implement ioctl()
  12.                 13Sep92    MN    Always complete write
  13.                 06Dec92    MN    Check flags
  14.                 17Dec92    MN    Forgot to clear errno in PPCSocketDomain::socket()
  15. Last        :    17Dec92
  16. *********************************************************************/
  17.  
  18. #include "GUSI_P.h"
  19.  
  20. #include <Errors.h>
  21. #include <ADSP.h>
  22. #include <Devices.h>
  23. #include <GestaltEqu.h>
  24. #include <PPCToolBox.h>
  25. #include <PLStringFuncs.h>
  26.  
  27. #include <sys/types.h>
  28.  
  29. #pragma force_active on
  30.  
  31. class PPCSocket;                             // That's what this file's all about
  32.  
  33. struct PPCPB {
  34.     PPCParamBlockRec    ppc;
  35.     PPCSocket *            sock;
  36. };
  37.  
  38. class PPCSocket : public Socket    {        
  39.     friend class PPCSocketDomain;    
  40.     friend pascal void ReadHellHound(PPCPB * pb);
  41.     friend pascal void WriteHellHound(PPCPB * pb);
  42.  
  43.     enum {
  44.         notBound, 
  45.         notOpen,
  46.         isListening,
  47.         isOpen,
  48.         isAccepted}        status;
  49.     Boolean                nonblocking;
  50.     Boolean                readPending;
  51.     Boolean                writePending;
  52.     Boolean                readShutDown;
  53.     Boolean                writeShutDown;
  54.     LocationNameRec    location;
  55.     PPCPortRec            port;
  56.     LocationNameRec    peerLoc;
  57.     PPCPortRec            peerPort;
  58.     PPCPB                    pb;
  59.     PPCPB    *                rpb;
  60.     RingBuffer *        rb;
  61.     RingBuffer *        wb;
  62.     
  63.                     PPCSocket();
  64.                     PPCSocket(const PPCSocket & acceptFrom);
  65.                     
  66.     virtual         ~PPCSocket();
  67.     
  68.     int            Alloc();
  69.     void            HellHoundsOnMyTrail();
  70. public:
  71.     virtual int    bind(void * name, int namelen);
  72.     virtual int getsockname(void * name, int * namelen);
  73.     virtual int getpeername(void *name, int *namelen);
  74.     virtual int    fcntl(unsigned int cmd, int arg);
  75.     virtual int listen(int qlen);
  76.     virtual int connect(void * address, int addrlen);
  77.     virtual Socket * accept(void * address, int * addrlen);
  78.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  79.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  80.     virtual int shutdown(int how);
  81.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  82.     virtual int    ioctl(unsigned int request, void *argp);
  83. };    
  84.  
  85. class PPCSocketDomain : public SocketDomain {
  86.     Boolean    ppcInit;
  87. public:
  88.     PPCSocketDomain();
  89.     
  90.     virtual    Socket *     socket(int type, short protocol);
  91.     virtual     int             choose(
  92.                                     int         type, 
  93.                                     char *     prompt, 
  94.                                     void *     constraint,        
  95.                                     int         flags,
  96.                                     void *     name, 
  97.                                     int *     namelen);
  98. };
  99.  
  100. PPCSocketDomain    PPCSockets;
  101.  
  102. /************************ PPC Toolbox initialization ************************/
  103.  
  104. pascal OSErr PPCInit_P()
  105. {
  106.     OSErr        err;
  107.     long        attr;
  108.         
  109.     if (err = Gestalt(gestaltPPCToolboxAttr, &attr))
  110.         return err;
  111.         
  112.     if (!(attr & gestaltPPCSupportsRealTime))
  113.         err = PPCInit();
  114.  
  115.     return err;
  116. }
  117.  
  118. Feature hasPPC(PPCInit_P);
  119.  
  120. /********************* Link stuffing procedures *********************/
  121.  
  122. #pragma segment GUSIResident
  123.  
  124. pascal void ReadHellHound(PPCPB * pb)
  125. {
  126.     if (!pb->sock->rb)                                    // We're closing
  127.         return;
  128.         
  129.     RingBuffer &     buf     =    *pb->sock->rb;
  130.     PPCReadPBRec & p         =    pb->ppc.readParam;
  131.     Boolean &        pend    =    pb->sock->readPending;
  132.     
  133.     if (buf.Locked())
  134.         buf.Later(Deferred(ReadHellHound), pb);
  135.     else    {
  136.         buf.Later(nil, nil);
  137.         if (pend) {
  138.             if (p.ioResult)    {
  139.                 pb->sock->readShutDown    =    true;
  140.                 
  141.                 return;
  142.             }
  143.             
  144.             buf.Validate(p.actualLength);
  145.             pend    =    false;
  146.         }
  147.         
  148.         if (!buf.Free()) 
  149.             buf.Later(Deferred(ReadHellHound), pb);
  150.         else {
  151.             long    max    =    1000000;
  152.             
  153.             p.ioCompletion    =    PPCCompProcPtr(ReadHellHound);
  154.             p.bufferPtr        =    buf.Producer(max);
  155.             p.bufferLength    =    max;
  156.             pend                =    true;
  157.             
  158.             PPCReadAsync(&p);
  159.         }
  160.     }
  161. }
  162.  
  163. pascal void WriteHellHound(PPCPB * pb)
  164. {
  165.     if (!pb->sock->wb)                                    // We're closing
  166.         return;
  167.         
  168.     RingBuffer &      buf     =    *pb->sock->wb;
  169.     PPCWritePBRec & p         =    pb->ppc.writeParam;
  170.     Boolean &         pend    =    pb->sock->writePending;
  171.     
  172.     if (buf.Locked())
  173.         buf.Later(Deferred(WriteHellHound), pb);
  174.     else    {
  175.         buf.Later(nil, nil);
  176.         
  177.         if (pend) {
  178.             if (p.ioResult)    {
  179.                 pb->sock->writeShutDown    =    true;
  180.                 
  181.                 return;
  182.             }
  183.  
  184.             buf.Invalidate(p.actualLength);
  185.             pend    =    false;
  186.         }
  187.         
  188.         if (!buf.Valid()) 
  189.             buf.Later(Deferred(WriteHellHound), pb);
  190.         else {
  191.             long    max    =    1000000;
  192.             
  193.             p.ioCompletion    =    PPCCompProcPtr(WriteHellHound);
  194.             p.bufferPtr        =    buf.Consumer(max);
  195.             p.bufferLength    =    max;
  196.             p.more            =    false;
  197.             p.userData        =    0;
  198.             p.blockCreator    =    'GU╖I';
  199.             p.blockType        =    'GU╖I';
  200.             pend                =    true;
  201.             
  202.             PPCWriteAsync(&p);
  203.         }
  204.     }
  205. }
  206.  
  207. #pragma segment GUSI
  208.  
  209. /************************ PPCSocket members ************************/
  210.  
  211. PPCSocket::PPCSocket()
  212. {
  213.     status            =    PPCSocket::notBound;
  214.     nonblocking        =    false;
  215.     pb.sock            =    this;
  216.     rpb                =    nil;
  217.     rb                    =    nil;
  218.     wb                    =    nil;
  219.     readPending        =    false;
  220.     writePending    =    false;
  221.     readShutDown    =    false;
  222.     writeShutDown    =    false;
  223. }
  224.  
  225. PPCSocket::PPCSocket(const PPCSocket & acceptFrom)
  226. {
  227.     status            =    PPCSocket::isAccepted;
  228.     nonblocking        =    acceptFrom.nonblocking;
  229.     pb.ppc            =    acceptFrom.pb.ppc;
  230.     pb.sock            =    this;
  231.     rpb                =    nil;
  232.     rb                    =    nil;
  233.     wb                    =    nil;
  234.     readPending        =    false;
  235.     writePending    =    false;
  236.     readShutDown    =    false;
  237.     writeShutDown    =    false;
  238.     location            =    acceptFrom.location;
  239.     port                =    acceptFrom.port;
  240.     peerLoc            =    acceptFrom.peerLoc;
  241.     peerPort            =    acceptFrom.peerPort;
  242. }
  243.  
  244. PPCSocket::~PPCSocket()
  245. {
  246.     if (rb)    {
  247.         delete rb;
  248.         
  249.         rb = nil;
  250.     }
  251.     
  252.     if (wb)    {
  253.         delete wb;
  254.         
  255.         wb = nil;
  256.     }
  257.  
  258.     switch (status) {
  259.     case PPCSocket::isAccepted:
  260.         PPCEndSync(&pb.ppc.endParam);
  261.         
  262.         break;                                        // Don't close the port
  263.     case PPCSocket::isListening:
  264.     case PPCSocket::isOpen:
  265.         PPCEndSync(&pb.ppc.endParam);
  266.  
  267.         /* Fall through */
  268.     case PPCSocket::notOpen:
  269.         PPCCloseSync(&pb.ppc.closeParam);
  270.         /* Fall through */
  271.     case PPCSocket::notBound:
  272.         break;
  273.     }
  274. }
  275.  
  276. int PPCSocket::Alloc()
  277. {
  278.     if (!rpb)
  279.         rpb    =    new PPCPB;
  280.     
  281.     if (!rpb)
  282.         goto error;
  283.     
  284.     rpb->sock    =    this;
  285.     
  286.     if (!rb)
  287.         rb    =    new RingBuffer(2048);
  288.     
  289.     if (!rb)    
  290.         goto error;
  291.     if (!*rb)
  292.         goto errRB;
  293.     
  294.     if (!wb)
  295.         wb =    new RingBuffer(2048);
  296.     
  297.     if (!wb)    
  298.         goto errRB;
  299.     if (!*wb)
  300.         goto errWB;
  301.     
  302.     return 0;
  303.  
  304. errWB:
  305.     delete wb;
  306.     
  307.     wb    =    nil;
  308. errRB:
  309.     delete rb;
  310.     
  311.     rb    =    nil;
  312. error:
  313.     return GUSI_error(ENOMEM);
  314. }
  315.  
  316. void PPCSocket::HellHoundsOnMyTrail()
  317. {
  318.     rpb->ppc.readParam.sessRefNum        =    pb.ppc.startParam.sessRefNum;
  319.     
  320.     ReadHellHound(rpb);
  321.     WriteHellHound(&pb);
  322. }
  323.  
  324. int PPCSocket::fcntl(unsigned int cmd, int arg)
  325. {
  326.     switch (cmd)    {
  327.     case F_GETFL:
  328.         if (nonblocking)
  329.             return FNDELAY;
  330.         else
  331.             return 0;
  332.     case F_SETFL:
  333.         if (arg & FNDELAY)
  334.             nonblocking = true;
  335.         else
  336.             nonblocking = false;
  337.             
  338.         return 0;
  339.     default:
  340.         return GUSI_error(EOPNOTSUPP);
  341.     }
  342. }
  343.  
  344. int PPCSocket::ioctl(unsigned int request, void *argp)
  345. {
  346.     switch (request)    {
  347.     case FIONBIO:
  348.         nonblocking    =    (Boolean) *(long *) argp;
  349.         
  350.         return 0;
  351.     case FIONREAD:
  352.         switch(status)    {
  353.         case PPCSocket::isAccepted:
  354.         case PPCSocket::isOpen:
  355.             break;
  356.         default:
  357.             return GUSI_error(ENOTCONN);    
  358.         }
  359.     
  360.         *(unsigned long *) argp    = rb->Valid();
  361.         
  362.         return 0;
  363.     default:
  364.         return GUSI_error(EOPNOTSUPP);
  365.     }
  366. }
  367.  
  368. int PPCSocket::bind(void *sa_name, int)
  369. {
  370.     struct sockaddr_ppc *    addr = (struct sockaddr_ppc *) sa_name;
  371.     
  372.     if (addr->family != AF_PPC)
  373.         GUSI_error(EAFNOSUPPORT);
  374.         
  375.     if (status != PPCSocket::notBound)
  376.         return GUSI_error(EINVAL);
  377.     
  378.     location = addr->location;
  379.     port        = addr->port;
  380.     
  381.     pb.ppc.openParam.ioCompletion        =    nil;
  382.     pb.ppc.openParam.serviceType        =    ppcServiceRealTime;
  383.     pb.ppc.openParam.resFlag            =    0;
  384.     pb.ppc.openParam.portName            =    &port;
  385.     pb.ppc.openParam.locationName        =    &location;
  386.     pb.ppc.openParam.networkVisible    =    true;
  387.     
  388.     switch (PPCOpenSync(&pb.ppc.openParam))    {
  389.     case noErr:
  390.         break;
  391.     case nameTypeErr:
  392.     case badReqErr:
  393.     case badPortNameErr:
  394.     case badLocNameErr:
  395.         return GUSI_error(EINVAL);
  396.     case noGlobalsErr:
  397.         return GUSI_error(ENOMEM);
  398.     case portNameExistsErr:
  399.     case nbpDuplicate:
  400.         return GUSI_error(EADDRINUSE);
  401.     default:
  402.         return GUSI_error(EFAULT);
  403.     }
  404.     
  405.     status =    PPCSocket::notOpen;
  406.     
  407.     return 0;
  408. }
  409.  
  410. int PPCSocket::getsockname(void *name, int *namelen)
  411. {
  412.     struct sockaddr_ppc    addr;
  413.     
  414.     addr.family            =    AF_PPC;
  415.     addr.location        =    location;
  416.     addr.port            =    port;
  417.     
  418.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(struct sockaddr_ppc)));
  419.     
  420.     return 0;
  421. }
  422.  
  423. int PPCSocket::getpeername(void *name, int *namelen)
  424. {
  425.     struct sockaddr_ppc    addr;
  426.     
  427.     addr.family            =    AF_PPC;
  428.     addr.location        =    peerLoc;
  429.     addr.port            =    peerPort;
  430.     
  431.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(struct sockaddr_ppc)));
  432.     
  433.     return 0;
  434. }
  435.  
  436. int PPCSocket::listen(int)
  437. {    
  438.     switch (status)    {
  439.     case PPCSocket::notBound:
  440.         return GUSI_error(EINVAL);
  441.     case PPCSocket::isOpen:
  442.     case PPCSocket::isListening:
  443.         return GUSI_error(EISCONN);
  444.     default:
  445.         break;
  446.     }
  447.     
  448.     pb.ppc.informParam.autoAccept        =    true;
  449.     pb.ppc.informParam.portName            = &peerPort;
  450.     pb.ppc.informParam.locationName     = &peerLoc;
  451.     pb.ppc.informParam.userName            =    nil;
  452.     
  453.     if (PPCInformAsync(&pb.ppc.informParam))
  454.         return GUSI_error(EINVAL);
  455.         
  456.     status = PPCSocket::isListening;
  457.     
  458.     return 0;
  459. }
  460.  
  461. int PPCSocket::connect(void *sa_name, int)
  462. {
  463.     Boolean                         guest;
  464.     struct sockaddr_ppc *    addr = (struct sockaddr_ppc *) sa_name;
  465.     Str32                            uname;
  466.     
  467.     switch (status)    {
  468.     case PPCSocket::notBound:
  469.         return GUSI_error(EINVAL);
  470.     case PPCSocket::isOpen:
  471.     case PPCSocket::isListening:
  472.     case PPCSocket::isAccepted:
  473.         return GUSI_error(EISCONN);
  474.     default:
  475.         break;
  476.     }
  477.     
  478.     if (Alloc())
  479.         return -1;
  480.  
  481.     if (addr->family != AF_PPC)
  482.         GUSI_error(EAFNOSUPPORT);
  483.     
  484.     peerLoc    = addr->location;
  485.     peerPort    = addr->port;
  486.     uname[0] = 0;
  487.         
  488.     pb.ppc.startParam.serviceType        =    ppcServiceRealTime;
  489.     pb.ppc.startParam.resFlag            =    0;
  490.     pb.ppc.startParam.portName            = &peerPort;
  491.     pb.ppc.startParam.locationName     = &peerLoc;
  492.     pb.ppc.startParam.userData            =    0;
  493.     
  494.     if (StartSecureSession(&pb.ppc.startParam, uname, true, true, &guest, "\p"))
  495.         return GUSI_error(EINVAL);
  496.         
  497.     status                                     =     PPCSocket::isOpen;
  498.     
  499.     HellHoundsOnMyTrail();
  500.     
  501.     return 0;
  502. }
  503.  
  504. Socket * PPCSocket::accept(void * address, int * addrlen)
  505. {
  506.     PPCSocket    *    newsock;
  507.     
  508.     if (status != PPCSocket::isListening)
  509.         return (Socket *) GUSI_error_nil(ENOTCONN);
  510.  
  511.     if (nonblocking && pb.ppc.informParam.ioResult == 1)
  512.         return (Socket *) GUSI_error_nil(EWOULDBLOCK);
  513.         
  514.     SPINP(pb.ppc.informParam.ioResult == 1, SP_MISC, 0);
  515.  
  516.     if (pb.ppc.informParam.ioResult)
  517.         return (Socket *) GUSI_error_nil(EFAULT);
  518.     
  519.     newsock    =    new PPCSocket(*this);
  520.  
  521.     if (!newsock)
  522.         return (Socket *) GUSI_error_nil(ENOMEM);
  523.         
  524.     if (newsock->Alloc())    {
  525.         delete newsock;
  526.         
  527.         return (Socket *) GUSI_error_nil(ENOMEM);
  528.     }
  529.     
  530.     newsock->HellHoundsOnMyTrail();
  531.                                                     
  532.     if (address && addrlen)
  533.         getpeername(address, addrlen);
  534.  
  535.     pb.ppc.informParam.autoAccept        =    true;
  536.     pb.ppc.informParam.portName        = &peerPort;
  537.     pb.ppc.informParam.locationName     = &peerLoc;
  538.     pb.ppc.informParam.userName        =    nil;
  539.     
  540.     PPCInformAsync(&pb.ppc.informParam);
  541.         
  542.     return newsock;
  543. }
  544.  
  545. int PPCSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int *)
  546. {
  547.     long    len    =    buflen;
  548.     
  549.     if (from)
  550.         return GUSI_error(EOPNOTSUPP);
  551.     if (flags)
  552.         return GUSI_error(EOPNOTSUPP);
  553.     
  554.     switch(status)    {
  555.     case PPCSocket::isAccepted:
  556.     case PPCSocket::isOpen:
  557.         break;
  558.     default:
  559.         return GUSI_error(ENOTCONN);    
  560.     }
  561.     
  562.     if (!rb->Valid())    
  563.         if (readShutDown)
  564.             return 0;
  565.         else if (nonblocking)
  566.             return GUSI_error(EWOULDBLOCK);
  567.         else
  568.             SPIN(!rb->Valid(), SP_STREAM_READ, 0);
  569.     
  570.     rb->Consume(Ptr(buffer), len);
  571.     
  572.     return len;
  573. }
  574.  
  575. int PPCSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  576. {
  577.     long    len    =    buflen;
  578.     long    done    =    0;
  579.     
  580.     if (to)
  581.         return GUSI_error(EOPNOTSUPP);
  582.     if (flags)
  583.         return GUSI_error(EOPNOTSUPP);
  584.     
  585.     switch(status)    {
  586.     case PPCSocket::isAccepted:
  587.     case PPCSocket::isOpen:
  588.         break;
  589.     default:
  590.         return GUSI_error(ENOTCONN);    
  591.     }
  592.     
  593.     if (writeShutDown)
  594.         return GUSI_error(ESHUTDOWN);
  595.     
  596.     if (!wb->Free())
  597.         if (nonblocking)
  598.             return GUSI_error(EWOULDBLOCK);
  599.         
  600.     for (;;) {
  601.         wb->Produce(Ptr(buffer), len);
  602.         
  603.         done        +=    len;
  604.         
  605.         if (nonblocking)
  606.             break;
  607.         
  608.         buflen    -=    int(len);
  609.         
  610.         if (!buflen)
  611.             break;
  612.         
  613.         buffer     =    Ptr(buffer) + len;
  614.         len        =    buflen;
  615.         
  616.         SPIN(!wb->Free(), SP_STREAM_WRITE, 0);
  617.     }
  618.     
  619.     return done;
  620. }
  621.  
  622. int PPCSocket::shutdown(int how)
  623. {
  624.     if (how < 0 ||╩how > 2)
  625.         return GUSI_error(EINVAL);
  626.     
  627.     if (how)
  628.         writeShutDown    =    true;
  629.     if (!(how & 1))
  630.         readShutDown    =    true;
  631.         
  632.     return 0;
  633. }
  634.  
  635. int PPCSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * exception)
  636. {
  637.     int        goodies     =     0;
  638.     Boolean    error        =    false;
  639.  
  640.     switch(status)    {
  641.     case PPCSocket::isAccepted:
  642.     case PPCSocket::isOpen:
  643.     case PPCSocket::isListening:
  644.         break;
  645.     default:
  646.         return GUSI_error(ENOTCONN);    
  647.     }
  648.     
  649.     if (canRead)
  650.         if (status == PPCSocket::isListening && pb.ppc.informParam.ioResult != 1) {
  651.             *canRead =     true;
  652.             ++goodies;
  653.         } else if (rb) {
  654.             if (rb->Valid()) {
  655.                 *canRead =     true;
  656.                 ++goodies;
  657.             } else if (readShutDown) {
  658.                 *canRead =     false;
  659.                 error        =    true;
  660.             }
  661.         } else {
  662.             *canRead =     false;
  663.             error        =    true;
  664.         }
  665.     
  666.     if (canWrite)
  667.         if (*canWrite = wb && wb->Free())
  668.             ++goodies;
  669.         else
  670.             error    =    true;
  671.     
  672.     if (exception)
  673.         if (*exception = error)
  674.             ++goodies;
  675.     
  676.     return goodies;
  677. }
  678.  
  679. /********************* PPCSocketDomain member **********************/
  680.  
  681.  
  682. PPCSocketDomain::PPCSocketDomain()
  683.     :    SocketDomain(AF_PPC)    
  684. {
  685. }
  686.  
  687. Socket * PPCSocketDomain::socket(int type, short)
  688. {
  689.     PPCSocket * sock    =    nil;
  690.     
  691.     errno = 0;
  692.     
  693.     if (!hasPPC)
  694.         GUSI_error(EOPNOTSUPP);
  695.     else 
  696.         switch (type)    {
  697.         case SOCK_STREAM:
  698.             sock = new PPCSocket();
  699.             break;
  700.         default:
  701.             GUSI_error(ESOCKTNOSUPPORT);
  702.         }    
  703.     
  704.     if (sock && errno)    {
  705.         delete sock;
  706.         
  707.         return nil;
  708.     } else
  709.         return sock;
  710. }
  711.  
  712. int PPCSocketDomain::choose(int, char * prompt, void * constraint, int flags, void * name, int * namelen)
  713. {
  714.     sockaddr_ppc        addr;
  715.     char *                end;
  716.     Str255                promp;
  717.     PortInfoRec            info;
  718.     
  719.     if (flags & (CHOOSE_NEW | CHOOSE_DIR))
  720.         return GUSI_error(EINVAL);
  721.         
  722.     end         =     (char *) memccpy(promp+1, prompt, 0, 254);
  723.     promp[0]    =    end-(char *)promp-2;
  724.     
  725.     if (
  726.         PPCBrowser(
  727.             promp, 
  728.             "\p", 
  729.             false, 
  730.             &addr.location, 
  731.             &info, 
  732.             PPCFilterProcPtr(nil),
  733.             Str32(constraint))
  734.     )
  735.         return GUSI_error(EINTR);
  736.  
  737.     addr.family    =    AF_PPC;
  738.     addr.port    =    info.name;
  739.     
  740.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(sockaddr_ppc)));
  741.     
  742.     return 0;
  743. }
  744.